﻿using System.Collections.Generic;
using UnityEngine;
using Framework.Entity;


namespace BridgeShips.AI {
    /*
     * 
     *  EntityDetection
     */

    [System.Serializable]
    public class EntityDetection {
        public int ViewRadius { get { return m_ViewRadius; } }

        public int PitchNumber { get { return m_ShipPitchNumber; } }

        public int ViewAngle { get { return m_ViewAngle; } }

        public GameObject LastChasedTarget { get; set; }

        public List<IEntity> HandlerEntitys { get { return m_HandleEntitys; } }
        public List<IEntity> VisibleEntitys { get { return m_VisibleEntitys; } }
        public List<IEntity> StillInRangeEntitys { get { return m_StillInRangeEntitys; } }

        [SerializeField]
        [Tooltip( "Time it takes to look for targets again." )]
        private float m_TargetSearchDelay;

        [SerializeField]
        public Transform m_Transform;

        [SerializeField]
        [Range( 0, 360 )]
        [Tooltip( "Angle at which it can spot a Ship." )]
        private int m_ViewAngle = 120;

        [SerializeField]
        [Tooltip( "Radius around the AI at which it can spot a Ship" )]
        private int m_ViewRadius = 37;

        [SerializeField]
        [Tooltip( "Pitch Number of the Ship" )]
        private int m_ShipPitchNumber = 5;


        [SerializeField]
        [Tooltip( "Used for finding only specific types of targets." )]
        private LayerMask m_SpotMask;

        [SerializeField]
        [Tooltip( "Used to know what objects can be blocking our view from the AI." )]
        private LayerMask m_ObstacleMask;

        [SerializeField]
        public bool m_testAcitve = false;

        // The targets the AI is currently seeing.
        private List<IEntity> m_HandleEntitys = new List<IEntity>();

        private List<IEntity> m_VisibleEntitys = new List<IEntity>();

        private List<IEntity> m_StillInRangeEntitys = new List<IEntity>();

        // private Transform m_Transform;
        private float m_LastTargetFindTime;

        public void Initialize( Transform transform ) {
            m_Transform = transform;
        }

        public void Update( AIShip ship ) {
            if (m_TargetSearchDelay == 0 || HaveLinked())
                return;

            if (Time.time - m_LastTargetFindTime >= m_TargetSearchDelay) {
                //find entitys which in( m_ViewRadius) range;

                FindVisibleVehicleEntitys(ship);
                //caculate valid entitys still in range; 
                CaculEntityStillInRange();
                m_LastTargetFindTime = Time.time;
                VisibleEntitys.Clear();
                StateData.OverrideValue( HelpStrings.AI.IS_SHIP_IN_SIGHT, HasTarget(), ship.WorldState );
            }
        }

        public Transform EntityTransform() {
            return m_Transform;
        }

        public IEntity GetEnity() {
            var shipHander = m_Transform.GetComponent<AIEventHandler>();
            if (shipHander == null)
                return null;  
            return GameEntry.Instance.EntityManager.Get( shipHander.id.Get() );
        }

        /// <summary>
        /// Used to check if the AI has a target currently.
        /// </summary>
        /// <returns></returns>
        public bool HasTarget() {
            return m_StillInRangeEntitys.Count > 0;
        }

        public bool HaveLinked() {
            var shipHander = m_Transform.GetComponent<AIEventHandler>();
            if (shipHander != null) {
                return shipHander.IsLinked.Is( true );
            }
            return false;
        }

        public bool HasVisibleTarget() {
            return m_VisibleEntitys.Count > 0;
        }

        public IEntity GetRandomTarget() {
            return m_StillInRangeEntitys[Random.Range( 0, m_StillInRangeEntitys.Count )];
        }


        private void CaculEntityStillInRange() {

            for (int i = 0; i < VisibleEntitys.Count; i++) {
                if (!m_StillInRangeEntitys.Contains( m_VisibleEntitys[i] ))
                    m_StillInRangeEntitys.Add( m_VisibleEntitys[i] );
            }

            for (int x = 0; x < m_StillInRangeEntitys.Count; x++) {
                bool foundEqual = false;

                for (int y = 0; y < VisibleEntitys.Count; y++) {
                    if (VisibleEntitys[y].Get() == m_StillInRangeEntitys[x].Get())
                        foundEqual = true;
                }

                if (!foundEqual)
                    m_StillInRangeEntitys.Remove( m_StillInRangeEntitys[x] );
            }
        }

        private void FindVisibleVehicleEntitys(AIShip ship) {
            FindVehiclesInRange();
            for (int i = 0; i < HandlerEntitys.Count; i++) {
                Transform target = HandlerEntitys[i].Get().transform;
                Vector3 targetPos = target.position /*+ Vector3.up*/;
                targetPos.y = m_Transform.position.y;
                // Get the direction to the target.
                Vector3 dirToTarget = (targetPos - m_Transform.position).normalized;

                ShipTypes sType = ship.Settings.GetShipPattern();
               
                // Check if it's inside the viewAngle of the agent.
                for (int index = -1; index < 2; index += 2) {
                    float angle = 0.0f;
                    if (sType == ShipTypes.LineType)
                    {
                        angle = Vector3.Angle(m_Transform.forward * index, dirToTarget);
                    }
                    else
                    {
                        angle = Vector3.Angle(m_Transform.right * index, dirToTarget);
                    }
                    // Debug.LogError("angle = " + angle);
                    if (angle < m_ViewAngle / 2) {
                        // Check the distance.
                        float distToTarget = Vector3.Distance( m_Transform.position, targetPos );
                        // See if something is blocking the view to the target.
                        float rayDistance = m_ViewRadius * 0.5f;
                        if (!Physics.Raycast( m_Transform.position, dirToTarget, rayDistance, m_ObstacleMask )) {
                            //Debug.LogError( "distToTarget == " + distToTarget );
                            if(!VisibleEntitys.Contains(HandlerEntitys[i]))
                                 VisibleEntitys.Add( HandlerEntitys[i] );
                        }

                    }
                }
            }
        }

        private Collider[] GetCollidersInRange() {
            return Physics.OverlapSphere( m_Transform.position, m_ViewRadius, m_SpotMask );
        }

        private void FindVehiclesInRange() {
            if (GameEntry.Instance == null)
                return;

            m_HandleEntitys.Clear();
            var entitys = GameEntry.Instance.EntityManager.Entitys();
            foreach (var e in entitys) {
                var tranform = ((VehicleEntity)e).Transform();
                if (m_Transform.name != tranform.name) {
                    float distToTarget = Vector3.Distance( m_Transform.position, tranform.position );
                    if (distToTarget < m_ViewRadius) {
                        if (e.Get().GetComponentInParent<AIEventHandler>() != null)
                            m_HandleEntitys.Add( e );
                    }
                }
            }
        }
    }
}